﻿#include "qtserial.h"
#include "ui_qtserial.h"

#include <QMessageBox>
#include <QTextStream>
#include <QDebug>
#include <QTime>
#include <QTimer>
#include <iostream>
#include <QDebug>
#include <QString>

qtSerial::qtSerial(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::qtSerial)
{
    ui->setupUi(this);

    initSreial();
}



qtSerial::~qtSerial()
{
    delete ui;
    delete serial;
    delete time;
}

/*接收数据处理*/
void qtSerial::receDataSlot()
{
    int temp;

    static int i = 0;

    QString bytes = ui->tbRecvData->toPlainText();

    QByteArray tempBytes = serial->readAll();

    temp = tempBytes.length();
    serial_data->recevie_data += temp;
    receive_total += temp;

    if(stop_display_flag == false)
    {
        //接收的数据以16进制显示
        if(ui->ckbHexDisplay->checkState())
        {
            tempBytes = tempBytes.toHex(' ') + ' ';
        }

        //带时间显示
        if(ui->ckbShowRecvTime->checkState())
        {
            QString currntTime = QTime::currentTime().toString("hh:mm:ss.zzz");

            if(i == 1)      //当不带时间显示转换到带时间显示时，换行
            {
                bytes = bytes + "\n" + currntTime + ": " + QString::fromLocal8Bit(tempBytes) + "\n";

                i = 0;

            }
            else {
                bytes = bytes  + currntTime + ": " + QString::fromLocal8Bit(tempBytes) + "\n";
            }

        }
        else        //不带时间显示
        {
            i = 1;

            bytes =bytes + QString::fromLocal8Bit(tempBytes);
        }

        ui->tbRecvData->clear();

        ui->tbRecvData->setText(bytes);
    }
}

void qtSerial::openSerialPortSlot()
{
    if(serial->isOpen())
    {
        serial->close();
        ui->btnOpenSerial->setText("打开串口");

        //串口关闭后，串口参数可以改变
        ui->cbbSerialName->setEnabled(true);
        ui->cbbBaudRate->setEnabled(true);
        ui->cbbDataBits->setEnabled(true);
        ui->cbbStopBit->setEnabled(true);
        ui->cbbFlowControl->setEnabled(true);
        ui->cbbParityBit->setEnabled(true);

        ui->btnSendData->setEnabled(false);
        ui->ckbAutoSend->setCheckState(Qt::Unchecked);
    }
    else
    {
        serial->setPortName(ui->cbbSerialName->currentText());

        //设置波特率
        serial->setBaudRate(ui->cbbBaudRate->currentText().toInt());
        // serial->setBaudRate(614400);
        //设置数据位
        switch (ui->cbbDataBits->currentIndex()) {
        case 0:
            serial->setDataBits(QSerialPort::Data5);    break;
        case 1:
            serial->setDataBits(QSerialPort::Data6);    break;
        case 2:
            serial->setDataBits(QSerialPort::Data7);    break;
        case 3:
            serial->setDataBits(QSerialPort::Data8);    break;
        default:
            serial->setDataBits(QSerialPort::Data8);    break;
        }

        //设置停止位
        switch (ui->cbbStopBit->currentIndex()) {
        case 0:
            serial->setStopBits(QSerialPort::OneStop);              break;
        case 1:
            serial->setStopBits(QSerialPort::OneAndHalfStop);       break;
        case 2:
            serial->setStopBits(QSerialPort::TwoStop);              break;
        default:
            serial->setStopBits(QSerialPort::OneStop);              break;
        }

        //设置流控方式
        switch (ui->cbbFlowControl->currentIndex()) {
        case 0:
            serial->setFlowControl(QSerialPort::NoFlowControl);         break;
        case 1:
            serial->setFlowControl(QSerialPort::NoFlowControl);         break;
        case 2:
            serial->setFlowControl(QSerialPort::NoFlowControl);         break;
        default:
            serial->setFlowControl(QSerialPort::NoFlowControl);         break;
        }

        //设置校验方法
        switch (ui->cbbParityBit->currentIndex()) {
        case 0:
            serial->setParity(QSerialPort::NoParity);         break;
        case 1:
            serial->setParity(QSerialPort::EvenParity);         break;
        case 2:
            serial->setParity(QSerialPort::OddParity);         break;
        case 3:
            serial->setParity(QSerialPort::SpaceParity);         break;
        case 4:
            serial->setParity(QSerialPort::MarkParity);         break;
        default:
            serial->setParity(QSerialPort::NoParity);         break;
        }

        if ( !serial->open(QIODevice::ReadWrite) ) // 打开失败
        {
            QMessageBox::critical(this, tr("Error"), tr("串口不存在或者被其它程序占用！"), QMessageBox::Ok);
            return;
        }

        ui->btnOpenSerial->setText("关闭串口");

        //串口打开后，参数不能做改变
        ui->cbbSerialName->setEnabled(false);
        ui->cbbBaudRate->setEnabled(false);
        ui->cbbDataBits->setEnabled(false);
        ui->cbbStopBit->setEnabled(false);
        ui->cbbFlowControl->setEnabled(false);
        ui->cbbParityBit->setEnabled(false);

        //允许发送数据
        ui->btnSendData->setEnabled(true);
    }

}

void qtSerial::refreshSerialPortSlot()
{
    ui->cbbSerialName->clear();
    //获取可用串口号
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        serial->setPort(info);
        ui->cbbSerialName->addItem(serial->portName());
    }
}

void qtSerial::clearRecvSlot()
{
    ui->tbRecvData->clear();
}

void qtSerial::stopDisplaySlot()
{
    if(ui->btnStopDisplay->text() == "停止显示")
    {
       stop_display_flag = true;
       ui->btnStopDisplay->setText("恢复显示");
    }
    else
    {
        stop_display_flag = false;
        ui->btnStopDisplay->setText("停止显示");
    }
}


char ConvertHexChar(char ch)
{
    if((ch >= '0') && (ch <= '9'))
            return ch-0x30;
        else if((ch >= 'A') && (ch <= 'F'))
            return ch-'A'+10;
        else if((ch >= 'a') && (ch <= 'f'))
            return ch-'a'+10;
        else return (-1);
}

void StringToHex(QString str, QByteArray &senddata)
{
    int hexdata,lowhexdata;
    int hexdatalen = 0;
    int len = str.length();
    senddata.resize(len/2);
    char lstr,hstr;
    for(int i=0; i<len; )
    {
        //char lstr,
        hstr=str[i].toLatin1();
        if(hstr == ' ')
        {
            i++;
            continue;
        }
        i++;
        if(i >= len)
            break;
        lstr = str[i].toLatin1();
        hexdata = ConvertHexChar(hstr);
        lowhexdata = ConvertHexChar(lstr);
        if((hexdata == 16) || (lowhexdata == 16))
            break;
        else
            hexdata = hexdata*16+lowhexdata;
        i++;
        senddata[hexdatalen] = (int)hexdata;
        hexdatalen++;
    }
    senddata.resize(hexdatalen);
}

// 发送数据，写串口
void qtSerial::sendDataSlot()
{
    quint64 temp;
    QString str = ui->teSendData->toPlainText();

    if ( !str.isEmpty() )
    {
        if(ui->ckbHexSend->checkState())
        {
            StringToHex(str, SendBytes);
        }
        else {
            SendBytes = str.toLatin1();
        }
        temp= serial->write(SendBytes);
        send_total += temp;
        serial_data->send_data += temp;
    }
}

SerialSpeed qtSerial::statiticsSpeed(int speed_time_ms, SerialData &data)
{
    SerialSpeed speed;
    speed.send_spped = data.send_data * 8 / 1024.0 / speed_time_ms * 1000;
    speed.recevie_speed = data.recevie_data * 8 / 1024.0 /  speed_time_ms * 1000;
    return speed;
}

void qtSerial::autoSend(int state)
{
    if(serial->isOpen())
    {
        if(state == Qt::Checked)
        {
            ui->btnSendData->setEnabled(false);
            auto_send_timer->start(ui->sbAutoSendTime->value());
        }
        else {
            ui->btnSendData->setEnabled(true);
            auto_send_timer->stop();
        }
    }
    else
    {
        auto_send_timer->stop();
    }
}

void qtSerial::printSpeed()
{
    if(serial->isOpen())
    {
        int speed_time_temp;
        QString recevie_speed_str, sned_speed_str;
        *speed_new = QTime::currentTime();
        qDebug() << speed_new << speed_old;
        speed_time_temp = speed_old->msecsTo(*speed_new);
        qDebug() << speed_time_temp;
        *serial_speed = statiticsSpeed(speed_time_temp,*serial_data);
        *speed_old = *speed_new;
        serial_data->send_data = 0;
        serial_data->recevie_data = 0;

        recevie_speed_str = "接收速率 " + QString::number(serial_speed->recevie_speed, 'g', 5) + " Kbit/s\t\t";
        sned_speed_str = "发送速率 " + QString::number(serial_speed->send_spped, 'g', 5) + " Kbit/s";
        ui->statusBar->showMessage(recevie_speed_str+sned_speed_str);
    }
}

//初始化串口
void qtSerial::initSreial()
{
    send_total = 0;
    receive_total = 0;

    serial = new QSerialPort;

    time = new QTime;

    auto_send_timer = new QTimer;

    speed_timer = new QTimer;

    speed_old = new QTime;   // 用来辅助速率统计
    speed_new = new QTime;   // 用来辅助速率统计
    serial_speed = new SerialSpeed;
    serial_speed->send_spped = 0;
    serial_speed->recevie_speed = 0;

    serial_data = new SerialData;
    serial_data->send_data = 0;
    serial_data->recevie_data = 0;

    stop_display_flag = false;

    connect(serial, SIGNAL(readyRead()), this, SLOT(receDataSlot()));

    connect(auto_send_timer, SIGNAL(timeout()), this, SLOT(sendDataSlot()));

    connect(ui->btnOpenSerial,SIGNAL(clicked()),this,SLOT(openSerialPortSlot()));

    connect(ui->btnRefreshSerial,SIGNAL(clicked()),this,SLOT(refreshSerialPortSlot()));

    connect(ui->btnClearRece,SIGNAL(clicked()),this,SLOT(clearRecvSlot()));

    connect(ui->btnStopDisplay,SIGNAL(clicked()),this,SLOT(stopDisplaySlot()));

    connect(ui->btnSendData,SIGNAL(clicked()),this,SLOT(sendDataSlot()));

    connect(ui->ckbAutoSend, SIGNAL(stateChanged(int)), this, SLOT(autoSend(int)));

    connect(speed_timer, SIGNAL(timeout()),this,SLOT(printSpeed()));

    //设置默认波特率位115200
    ui->cbbBaudRate->setCurrentIndex(7);
    //设置默认数据位位8位
    ui->cbbDataBits->setCurrentIndex(3);
    //设置默认停止位位1位
    ui->cbbStopBit->setCurrentIndex(0);
    //设置默认流控为无流控
    ui->cbbFlowControl->setCurrentIndex(0);
    //设置默认校验位位无校验
    ui->cbbParityBit->setCurrentIndex(0);

    ui->btnSendData->setEnabled(false);

    speed_timer->start(1000);
}
